from django.views.decorators.csrf import csrf_exempt
from .deploy_config import model_serve_ip, model_serve_port
from rest_framework.exceptions import NotFound
from django.views.decorators.csrf import csrf_exempt
from .deploy_config import model_serve_ip, model_serve_port
from rest_framework.parsers import MultiPartParser, FormParser
import json
import logging
import os
import re
from shutil import make_archive

from django.core.files.storage import FileSystemStorage
from django.db.models import Max
from django.http import FileResponse
from pygments import highlight
from pygments.lexers import get_lexer_for_filename
from pygments.formatters import HtmlFormatter
from pygments.lexers.special import TextLexer
from rest_framework.generics import get_object_or_404
from rest_framework.schemas import ManualSchema, coreapi
from rest_framework.compat import coreapi, coreschema
from knowledge_extract.models import Snippet, Dataset, ModelRepo, Experiment
# from knowledge_extract.serializers import SnippetSerializer, UserSerializer, DatasetSerializer, \
#     ModelRepoSerializer, \
#     ExperimentSerializer, ExperimentListSerializer, DatasetListSerializer, \
#     AnnotationDatasetSerializer, PredictionSerializer
from knowledge_extract.serializers import *
from rest_framework import generics, renderers, status, serializers, mixins
from django.contrib.auth.models import User
from rest_framework import permissions
from modelops_backend.settings import BASE_DIR
from rest_framework.decorators import action, schema, api_view
from rest_framework.response import Response
from knowledge_extract.git_utils.git_ops import GitUtils
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import DatasetSerializer
from .models import Dataset
import knowledge_extract.service.pb.model_server_pb2 as pb
from rest_framework import parsers


task_map = {
                "命名实体识别": "ner",
                "关系抽取": "re",
                "实体关系联合抽取": "ner_re"
            }

# class FileUploadView(APIView):
#     parser_classes = (parsers.MultiPartParser, parsers.FormParser)  # 允许文件上传
#
#     def post(self, request, format=None):
#         serializer = DatasetSerializer(data=request.data)
#         if serializer.is_valid():
#             serializer.save()
#             return Response(serializer.data, status=status.HTTP_201_CREATED)
#         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


# @api_view(['GET'])
# def api_root(request):
#     return Response({
#         'users': reverse('user-list', request=request, ),
#         'snippets': reverse('snippet-list', request=request)
#     })
#
#
#
#
# class SnippetHighlight(generics.GenericAPIView):
#     queryset = Snippet.objects.all()
#     renderer_classes = (renderers.StaticHTMLRenderer,)
#
#     def get(self, request, *args, **kwargs):
#         snippet = self.get_object()
#         return Response(snippet.highlighted)
#
#
# class UserList(generics.ListAPIView):
#     queryset = User.objects.all()
#     serializer_class = UserSerializer
#
#
# class UserDetail(generics.RetrieveAPIView):
#     queryset = User.objects.all()
#     serializer_class = UserSerializer
#
#
# class SnippetList(generics.ListCreateAPIView):
#     """
#     列出或者创建一个snippet
#     """
#     permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
#     queryset = Snippet.objects.all()
#     serializer_class = SnippetSerializer
#
#     def perform_create(self, serializer):
#         serializer.save(owner=self.request.user)
#
#
# class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
#     permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
#     queryset = Snippet.objects.all()
#     serializer_class = SnippetSerializer

from rest_framework import viewsets
from loguru import logger

from .service.client import ModelServerClient


def get_not_null_params(request, key):
    r = request.GET.get(key, None)
    if r == '':
        return None
    return r


checkout_schema = ManualSchema(
    fields=[
        coreapi.Field(name="model_id", required=True, location="query",
                      schema=coreschema.Integer(description="ModelRepo的id")),
        coreapi.Field(name="branch_name", required=True, location="query",
                      schema=coreschema.String(description="分支名")),
    ]
)
get_file_content_schema = ManualSchema(
    fields=[
        coreapi.Field(name="file_name", required=True, location="query",
                      schema=coreschema.String(description="文件名")),
    ]
)
task_name_schema = ManualSchema(
    fields=[
        coreapi.Field(name="task", required=False, location="query",
                      schema=coreschema.String(description="任务名称")),
        coreapi.Field(name="name", required=False, location="query",
                      schema=coreschema.String(description="模型名称")),
    ]
)

task_area_name_schema = ManualSchema(
    fields=[
        coreapi.Field(name="task", required=False, location="query",
                      schema=coreschema.String(description="任务名称")),
        coreapi.Field(name="area", required=False, location="query",
                      schema=coreschema.String(description="领域名称")),
        coreapi.Field(name="name", required=False, location="query",
                      schema=coreschema.String(description="数据集名称")),
    ]
)


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    此视图自动提供`list`和`detail`操作。
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer


# class DatasetTransmission(mixins.CreateModelMixin,
#                     generics.GenericAPIView):
#     queryset = Dataset.objects.all()
#     serializer_class = AnnotationDatasetSerializer
#
#     def post(self, request, *args, **kwargs):
#         return self.create(request, *args, **kwargs)

class DatasetViewSet(viewsets.ModelViewSet):
    """
    对数据集的list、create、查看某个数据集等操作
    当返回的状态码为4xx时，说明出现了错误，错误信息在返回的json中的detail中
    如使用POST创建时,如数据集名称已经存在,或者task错误,则返回信息如下:
    {"name":["数据集 with this name already exists."],"task":["\"命名实体\" is not a valid choice."]}
    code: 400
    默认创建的数据集的用户为管理员
    """
    queryset = Dataset.objects.all().order_by('-id')
    serializer_class = DatasetSerializer
    parser_classes = (MultiPartParser, FormParser)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.grpc_client = ModelServerClient(ip=model_serve_ip, port=model_serve_port)  # 初始化客户端

    def get_serializer_class(self):
        # 根据不同的动作选择不同的序列化器
        if self.action == 'custom_create_dataset' or self.action == 'custom_update_dataset':
            return AnnotationDatasetSerializer
        return super().get_serializer_class()

    @action(detail=False, methods=['post'], url_path='custom_create')
    def custom_create_dataset(self, request):
        # 使用 AnnotationDatasetSerializer 来处理具体的数据
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            dataset = serializer.save()  # 假设所有者是已验证的用户
            with dataset.train_data.open(mode='rb') as f:
                train_data = f.read()
            with dataset.dev_data.open(mode='rb') as f:
                dev_data = f.read()
            with dataset.test_data.open(mode='rb') as f:
                test_data = f.read()
            with dataset.process_code.open(mode='rb') as f:
                process_code = f.read()

            if dataset.task in task_map:
                task = task_map[dataset.task]
            self.grpc_client.save_dataset(dataset.name, train_data, dev_data, test_data,
                                          process_code, task,
                                          os.path.splitext(dataset.train_data.name)[-1])
            # 处理文件保存等后续动作
            return Response(self.serializer_class(dataset).data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['put'], url_path='custom_update')
    def custom_update_dataset(self, request):
        # 从请求中获取name
        name = request.data.get('name')
        if not name:
            return Response({"detail": "Missing 'name' parameter."},
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            # 查找具有该name的Dataset实例
            dataset = Dataset.objects.get(name=name)
        except Dataset.DoesNotExist:
            return Response({"detail": f"Dataset with name '{name}' does not exist."},
                            status=status.HTTP_404_NOT_FOUND)

        # 使用AnnotationDatasetSerializer更新实例
        serializer = self.get_serializer(instance=dataset, data=request.data, partial=True)

        if serializer.is_valid():
            updated_dataset = serializer.save()  # 调用update方法
            with updated_dataset.train_data.open(mode='rb') as f:
                train_data = f.read()
            with updated_dataset.dev_data.open(mode='rb') as f:
                dev_data = f.read()
            with updated_dataset.test_data.open(mode='rb') as f:
                test_data = f.read()
            with updated_dataset.process_code.open(mode='rb') as f:
                process_code = f.read()

            if updated_dataset.task in task_map:
                task = task_map[updated_dataset.task]
            self.grpc_client.save_dataset(updated_dataset.name, train_data, dev_data, test_data,
                                          process_code, task,
                                          os.path.splitext(updated_dataset.train_data.name)[-1])
            return Response(self.serializer_class(updated_dataset).data, status=status.HTTP_200_OK)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['get'], url_path='recommend')
    def recommend(self, request,pk=None):
        # 获取当前实例
        instance = self.get_object()
        # 获取数据集名称和任务
        task = task_map[instance.task]
        dataset = instance.name
        # 向gRPC发请求
        resp = self.grpc_client.recommend(task,dataset)
        model_name = resp.model
        try:
            model_instance = ModelRepo.objects.get(model_name=model_name)
        except ModelRepo.DoesNotExist:
            raise NotFound(detail=f"Model with name '{model_name}' not found.")

        serializer = ModelRepoSerializer(model_instance)
        return Response(serializer.data,status=status.HTTP_200_OK)





    def list(self, request, *args, **kwargs):
        """
        list操作只返回基本信息,支持分页,支持按照名字进行模糊查询(包含关系),可以按照领域和任务进行划分
        如:http://127.0.0.1:8000/datasets/?area=新闻&task=命名实体识别&name=aa&page=1
        http://127.0.0.1:8000/datasets/id 返回某个数据集的详细信息
        """
        # 通过查询字符串获取除了Model字段以外的参数
        area = get_not_null_params(request, 'area')
        task = get_not_null_params(request, 'task')
        name = get_not_null_params(request, 'name')
        dataset_list = Dataset.objects.only('id', 'name', 'short_description', 'created',
                                            'owner__username', 'experiment_times', 'task',
                                            'area').order_by('-id')
        if area:
            dataset_list = dataset_list.filter(area=area)
        if task:
            dataset_list = dataset_list.filter(task=task)
        if name:
            dataset_list = dataset_list.filter(name__contains=name)

        page = self.paginate_queryset(dataset_list)
        # if page is not None:
        #     serializer = self.get_serializer(page, many=True)
        #     return self.get_paginated_response(serializer.data)
        # else:
        #     serializer = self.get_serializer(page, many=True)
        #     result_set = serializer.data
        #     return Response(result_set)
        serializer = DatasetListSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)

    def retrieve(self, request, *args, **kwargs):
        """
        查看某个数据集的详细信息
        """
        instance = self.get_object()
        if instance.train_data_path != '':
            if instance.train_data_path != instance.train_data.path:
                instance.train_data_path = instance.train_data.path
            if instance.sample == '':
                sample_size = request.GET.get('sample_size', default=3)
                sample_data = []
                try:
                    with open(instance.train_data_path, 'r', encoding='utf-8') as f:
                        for i in range(sample_size):
                            sample_data.append(json.loads(f.readline().strip()))
                except Exception as e:
                    sample_data = []
                    logger.error(e)
                instance.sample = json.dumps(sample_data, ensure_ascii=False)
            if instance.download_url == '':
                file_path = instance.train_data_path
                file_name = file_path.split(str(BASE_DIR))[-1].replace("\\", "/")
                instance.download_url = 'http://' + request.get_host() + file_name

            instance.save()

        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    def perform_create(self, serializer):
        if self.request.user.username != '':
            serializer.save(owner=self.request.user)
        else:
            super().perform_create(serializer)

    @action(detail=True, methods=['get'], url_path='download')
    def download(self, request, *args, **kwargs):
        """
        前端使用此方式下载数据集,浏览器会自动下载
        2.15更新:打包成zip下载
        """
        instance = self.get_object()
        dataset_name = instance.name
        all_file = []
        file_field = ["train_data", "dev_data", "test_data", "process_code"]
        for field in file_field:
            if getattr(instance, field):
                all_file.append(getattr(instance, field).path)
        import zipfile

        def format_file_name(file):
            base_name = os.path.basename(file)
            mode = base_name.split('.')[0].split("_")[0]
            format = base_name.split('.')[-1]
            return "{}.{}".format(mode, format)

        zip_file_path = os.path.join(BASE_DIR, "tmp", dataset_name + '.zip')
        # zip_file = zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED)
        if os.path.exists(zip_file_path):
            os.remove(zip_file_path)
        for file in all_file:
            with zipfile.ZipFile(zip_file_path, "a", zipfile.ZIP_DEFLATED) as z:
                z.write(file, format_file_name(file))
                print("add file: {}".format(file))
        # file_path = instance.train_data.path
        # file_name = file_path.split(str(BASE_DIR))[-1].replace("\\", "/").split('/')[-1]
        # file_format = file_name.split('.')[-1]
        file = open(zip_file_path, 'rb')
        response = FileResponse(file)
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = 'attachment;filename="{}"'.format(
            "{}.{}".format(instance.name, "zip"))
        return response

    @action(detail=False, methods=['get'], url_path='download_by_name')
    def download_by_name(self, request, *args, **kwargs):
        """
        使用数据集的名称下载数据集,不推荐前端使用
        sample:/datasets/download_by_name/?name=数据集名称
        """
        name = get_not_null_params(request, 'name')
        if name:
            instance = Dataset.objects.get(name=name)
            file_path = instance.train_data.path
            file_name = file_path.split(str(BASE_DIR))[-1].replace("\\", "/").split('/')[-1]
            file_format = file_name.split('.')[-1]
            file = open(file_path, 'rb')
            response = FileResponse(file)
            response['Content-Type'] = 'application/octet-stream'
            response['Content-Disposition'] = 'attachment;filename="{}"'.format(
                "{}.{}".format(instance.name, file_format))
            return response
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)

    @action(detail=True, methods=['get'], url_path='experiments')
    def get_experiments(self, request, *args, **kwargs):
        """
        获取某个数据集的所有实验
        """
        instance = self.get_object()
        experiment_list = Experiment.objects.filter(dataset_id=instance.id)
        page = self.paginate_queryset(experiment_list)
        serializer = ExperimentListSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)


class ExperimentViewSet(viewsets.ModelViewSet):
    """
    list:
        获取所有实验信息
    create:
        创建一个实验
    retrieve:
        获取某个实验的详细信息
    update:
        更新某个实验的信息
    partial_update:
        更新某个实验的部分信息
    destroy:
        删除某个实验
    """
    queryset = Experiment.objects.all()
    serializer_class = ExperimentSerializer

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.grpc_client = ModelServerClient(ip=model_serve_ip, port=model_serve_port)  # 初始化客户端

    def get_serializer_class(self):
        if self.action == 'predict':
            return PredictionSerializer
        elif self.action == 'run_active_learning':
            return SamplingSerializer
        else:
            return super().get_serializer_class()


    def perform_create(self, serializer):
        """
        创建实验，开始训练模型，若已有模型，则对其进行更新
        """
        if self.request.user.username != '':
            instance = serializer.save(owner=self.request.user, run_status='running')
        else:
            instance = serializer.save(run_status='running')
        dataset = serializer.validated_data['dataset_name']
        model = serializer.validated_data['model_name']
        task = task_map[serializer.validated_data['task']]
        model_config = serializer.validated_data['model_config']
        # print(project, dataset)
        # assert dataset or project
        # if not dataset:
        #     result = self.create_experiment(model, project, task, model_config)
        # else:
        #     result = self.create_experiment(model, project, task, model_config, dataset)
        # if project:
        #     serializer.save(project=project, model_status='running')
        # else:
        #     serializer.save(model_status='running')

        result = self.create_experiment(model, instance.id, task, model_config, dataset=dataset)
        return Response(result)

    def create_experiment(self, model, project, task, input_config=None, dataset=None):
        """
        创建实验并开始模型训练。

        Args:
            model: 模型名称。
            project: 项目ID。
            task: 训练任务类型。
            input_config (str, optional): 传入的模型配置，JSON格式的字符串。
            dataset (str, optional): 使用的数据集名称。

        Returns:
            str: 模型服务器响应的消息。
        """
        # 解析输入配置，更新模型配置
        if input_config and len(input_config):
            input_config = json.loads(input_config)
        # TODO：后期删掉
        if dataset == 'WebNLG' or dataset == 'NYT':
            dataset = 'conll2003'
        # 当使用已有数据集进行训练时，注意此时用project_id来充当experiment_id
        response = self.grpc_client.create_experiment(
            task=task, model=model, dataset=dataset,
            version=0, experiment_id=project,
            model_config=input_config['model_config'],
            optimizer_config=input_config['optimizer'],
        )

        # 获取模型服务器响应的消息
        result = response.message
        return result

    @action(detail=True, methods=['post'], url_path='active_learning')
    def run_active_learning(self, request, pk=None):
        """
        接受一个实验ID，返回主动学习采样到的待预测样本在整个数据集中的索引列表
        """
        try:
            experiment = self.get_object()
            serializer_class = self.get_serializer_class()
            serializer = serializer_class(data=request.data)
            if serializer.is_valid():
                sampling_dataset = serializer.validated_data['sampling_dataset']
                sampling_task = serializer.validated_data['sampling_task']
                sampling_num = serializer.validated_data['sampling_num']
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            resp = self.grpc_client.run_active_learning(
                                                         task=task_map[experiment.task],
                                                         model=experiment.model_name,
                                                         dataset=experiment.dataset_name,
                                                         version=0,
                                                         experiment_id=int(pk),
                                                         model_config=
                                                         json.loads(experiment.model_config)[
                                                             'model_config'],optimizer_config=
                                                         json.loads(experiment.model_config)[
                                                             'optimizer'],sampling_dataset=sampling_dataset,sampling_task=sampling_task,sampling_num=sampling_num)
            indices = json.loads(resp.message)
            return Response(indices, status=status.HTTP_200_OK)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(detail=True, methods=['post'], url_path='predict')
    def predict(self, request, pk=None):
        """
        接受一个实验ID和待预测数据，返回预测结果
        """
        def find_offset(text, pattern):
            match = re.search(pattern, text)
            if match:
                span = match.span()
                return span[0], span[1]
            return -1, -1
        def contains_unicode(s):
            # 检查字符串中是否存在非ASCII字符
            return any(ord(char) > 127 for char in s)
        def remove_unicode_entities(prediction_result):
            # 将返回结果解析为 JSON 格式
            data = prediction_result
            # 定义一个正则表达式模式来匹配 Unicode 字符
            
            for item in data:
                filtered_entities = []
                for entity in item.get('entities', []):
                    # 检查实体中的每个部分是否包含非ASCII字符
                    if not any(contains_unicode(str(part)) for part in entity):
                        filtered_entities.append(entity)
                # 更新 entities 列表为过滤后的结果
                item['entities'] = filtered_entities
            
            # 将数据重新转回 JSON 字符串格式
            return data
        def convert_b_to_a(b_format):
            a_format = {}

            for relation in b_format:
                relation_name = relation[0]
                head_entity = relation[1]
                tail_entity = relation[2]

                head_entity_type, head_entity_name = head_entity[0], head_entity[3]
                tail_entity_type, tail_entity_name = tail_entity[0], tail_entity[3]

                if relation_name not in a_format:
                    a_format[relation_name] = []

                a_format[relation_name].append([head_entity_type, head_entity_name, tail_entity_type, tail_entity_name])

            return a_format

        # 使用 PredictionSerializer 来验证 predict_data
        serializer_class = self.get_serializer_class()
        serializer = serializer_class(data=request.data)
        if serializer.is_valid():
            raw_text = serializer.validated_data['raw_text']
            predict_data = serializer.validated_data['predict_data']
            # 预测逻辑
            try:
                experiment = self.get_object()
                text = [' '.join(e['words']) for e in predict_data]
                # 这是预测函数的调用，切换
                prediction_result = self.grpc_client.predict(text=text,
                                                             task=task_map[experiment.task],
                                                             model=experiment.model_name,
                                                             dataset=experiment.dataset_name,
                                                             version=0,
                                                             experiment_id=int(pk),
                                                             model_config=
                                                             json.loads(experiment.model_config)[
                                                                 'model_config'])
                raw_data = json.loads(prediction_result.message)
                data = remove_unicode_entities(raw_data)
                predictions = []
                # 遍历 entities 和 relations
                for item in data:
                    prediction_entity = []
                    # 解析实体
                    entities = item.get("entities", [])
                    for entity in entities:
                        entity_type, start_idx, end_idx, entity_name = entity
                        start_offset, end_offset = find_offset(raw_text, entity_name)
                        if start_offset != -1 and end_offset != -1:
                            prediction_entity.append({'label': entity_type, 'start_offset': start_offset,
                                                        'end_offset': end_offset})
                    relations = item.get("relations", [])
                    prediction_relation = convert_b_to_a(relations)
                    prediction = {'entity': prediction_entity, 'relation': prediction_relation}
                    predictions.append(prediction)
                return Response(predictions, status=status.HTTP_200_OK)
            except Exception as e:
                return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['get'])
    def visualize(self, request, *args, **kwargs):
        """返回实验的TensorBoard链接"""
        # 调用 gRPC 框架中的 get_running_metric
        experiment_ids = request.query_params.getlist('experiment_ids')
        # instance = self.get_object()
        # tensorboard_link = self.get_tensorboard_link(instance.id)
        tensorboard_link = self.get_tensorboard_link(','.join(experiment_ids))

        # 返回链接
        return Response(tensorboard_link)

    def get_tensorboard_link(self, experiment_ids):
        # 调用 gRPC 服务并获取链接
        # 假设 gRPC 客户端实例已经在类中可用，例如 self.grpc_client
        tensorboard_link = self.grpc_client.get_running_metric(
            experiment_ids=experiment_ids).message
        return tensorboard_link

    def list(self, request, *args, **kwargs):
        """
        获取所有实验信息
        可以对数据集、模型名称、任务类型进行筛选
        如/experiments/?dataset=数据集名称&model=模型名称&task=任务类型

        """
        dataset = get_not_null_params(request, 'dataset')
        task = get_not_null_params(request, 'task')
        model = get_not_null_params(request, 'model')
        # 确保查询集默认按创建时间降序排序
        experiment_list = Experiment.objects.order_by('-created').only(
            'id', 'dataset', 'model', 'task', 'owner', 'created',
            'run_status', 'model_version', 'description', 'metric'
        )
        if dataset:
            experiment_list = experiment_list.filter(dataset__name__icontains=dataset)
        if task:
            experiment_list = experiment_list.filter(task=task)
        if model:
            experiment_list = experiment_list.filter(model__model_name__icontains=model)

        page = self.paginate_queryset(experiment_list)
        serializer = ExperimentListSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)

    # def perform_create(self, serializer):
    #     """
    #     创建一个实验,同时对版本进行更新
    #     """
    #
    #     # 进行版本更新
    #     experiment = Experiment.objects.filter(model=serializer.validated_data['model'],
    #                                            run_status__in=['running', 'finished', 'deployed']).order_by(
    #         '-model_version').first()
    #     if experiment:
    #         model_version = experiment.model_version + 1
    #         if self.request.user.username != '':
    #             serializer.save(owner=self.request.user, model_version=model_version)
    #         else:
    #             serializer.save(model_version=model_version)
    #     else:
    #         if self.request.user.username != '':
    #             serializer.save(owner=self.request.user)
    #         else:
    #             serializer.save()



    # def retrieve(self, request, *args, **kwargs):
    #     """
    #     获取某个实验的详细信息
    #     """
    #     instance = self.get_object()
    #     serializer = ExperimentSerializer(instance)
    #     return_dict = serializer.data
    #     return_dict['model_version'] = 'v' + str(return_dict['model_version'])
    #     return Response(serializer.data)

    # def retrieve(self, request, *args, **kwargs):
    #     # 获取请求参数，即模型id
    #     # try:
    #     #     trained_model_id = kwargs.get('pk')
    #     #     # 查询出模型相关记录
    #     #     the_model = TrainedModel.objects.get(id=trained_model_id)
    #     # except TrainedModel.DoesNotExist:
    #     #     return Response({'error': 'No matching trained model found.'},
    #     #                     status=status.HTTP_404_NOT_FOUND)
    #     instance = self.get_object()
    #     # 如果是running状态
    #     if instance.run_status == 'running':
    #         # 实例化客户端
    #         client = ModelServerClient(ip='162.105.88.63', port=6000)
    #         # project_id = instance.project_id
    #         exp_id = int(kwargs.get('pk'))
    #         response = client.get_running_metric(experiment_id=exp_id)
    #         raw_metric = response.message
    #         raw_metric = json.loads(raw_metric)
    #         metric = {k: round(v[-1],4) for k, v in raw_metric.items()}
    #         # 获取最新指标记录
    #         instance.metric = json.dumps(metric)
    #
    #         # 保存更新到数据库
    #         instance.save()
    #
    #     # 返回最新指标记录
    #     return Response(ExperimentSerializer(instance).data)


class ModelRepoViewSet(viewsets.ModelViewSet):
    """
    返回模型库的基本信息
    """
    queryset = ModelRepo.objects.all()
    serializer_class = ModelRepoSerializer

    @schema(task_area_name_schema)
    def list(self, request, *args, **kwargs):
        """
        列出现有模型的信息
        支持按照任务进行筛选和分页,支持按照名称进行模糊查询, 参数为task=task_name name=model_name
        如http://127.0.0.1:8000/modelrepo/?task=命名实体识别&name=bert&page=1
        """
        task = get_not_null_params(request, 'task')
        name = get_not_null_params(request, 'name')

        if task:
            model_list = ModelRepo.objects.filter(task=task).order_by('-created')
        else:
            model_list = ModelRepo.objects.all().order_by('-created')
        if name:
            model_list = model_list.filter(model_name__icontains=name)
        page = self.paginate_queryset(model_list)

        serializer = ModelRepoSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)

    def perform_create(self, serializer):
        """
        根据基本信息创建模型库,生成模型库的GIT仓库
        """
        model_name = serializer.validated_data['model_name']
        git_util = GitUtils(model_name)
        result_status, result = git_util.create_git_repo()
        if not result_status:
            raise serializers.ValidationError(result)
        if self.request.user.username != '':
            serializer.save(owner=self.request.user)
        else:
            serializer.save()

    def destroy(self, request, *args, **kwargs):
        """
        删除模型库,同时自动删除模型库的GIT仓库
        """
        instance = self.get_object()
        model_name = instance.model_name
        logger.info("删除模型库:{}".format(model_name))
        git_util = GitUtils(model_name)
        result_status, result = git_util.delete_git_repo()
        logger.info(result_status, result)
        super().destroy(request, *args, **kwargs)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        model_name = instance.model_name
        serializer = self.get_serializer(instance)
        data_dict = dict(serializer.data)
        # git_util = GitUtils(instance.model_name)
        # result_status, result = git_util.get_repo_info()
        # logger.info((result_status, result))
        # if not result_status:
        #     raise serializers.ValidationError(result)
        # 实例化客户端

        client = ModelServerClient(ip=model_serve_ip, port=model_serve_port)

        response = client.get_model_params(
            model_name=model_name,
        )

        # 获取模型服务器响应的消息
        result = json.loads(response.message)
        data_dict.update({'parameter': result})
        return Response(data_dict)

    @action(detail=True, methods=['get'], url_path='file', schema=get_file_content_schema)
    def get_file_content(self, request, *args, **kwargs):
        """
        获取模型库中的文件内容
        如http://127.0.0.1:8011/modelrepos/1/file/?file_name=b.py
        其中1是指模型库的id, b.py是指模型库中的文件名
        返回高亮展示的文件内容
        """
        file_name = get_not_null_params(request, 'file_name')
        if file_name is None:
            return Response("file_name not provide", status=status.HTTP_400_BAD_REQUEST)
        instance = self.get_object()
        git_util = GitUtils(instance.model_name)
        result_status, content = git_util.get_file_content(file_name)
        if not result_status:
            raise serializers.ValidationError(content)
        if content == "":
            content = "文件内容为空"
        try:
            lexer = get_lexer_for_filename(file_name, code=content[:50])
        except Exception as e:
            lexer = TextLexer()
        formatter = HtmlFormatter(linenos=True, style='github', full=True, noclasses=True)
        return Response(highlight(content, lexer, formatter), status=status.HTTP_200_OK)
        # return Response(content)

    @action(detail=False, methods=['get'], url_path="check_out", schema=checkout_schema)
    def check_out(self, request, *args, **kwargs):
        """
        对仓库进行checkouts
        checkout之后,仓库中的文件会被更新为指定分支的版本
        需要重新获取仓库信息,刷新文件列表
        """
        model_id = get_not_null_params(request, 'model_id')
        branch_name = get_not_null_params(request, 'branch_name')

        if model_id is None or branch_name is None:
            return Response("model_id or branch_name not provide",
                            status=status.HTTP_400_BAD_REQUEST)

        instance = get_object_or_404(ModelRepo, pk=model_id)
        git_util = GitUtils(instance.model_name)
        if git_util.is_empty():
            return Response("仓库为空,请先上传文件", status=status.HTTP_400_BAD_REQUEST)

        result_status, result = git_util.checkout_branch(branch_name)
        if not result_status:
            raise serializers.ValidationError(result)
        return Response(result, status=status.HTTP_200_OK)

    @action(detail=True, methods=['get'], url_path="download")
    def download(self, request, *args, **kwargs):
        """
        打包成zip进行下载
        """
        instance = self.get_object()
        git_util = GitUtils(instance.model_name)
        if git_util.is_empty():
            return Response("仓库为空,请先上传文件", status=status.HTTP_400_BAD_REQUEST)
        parent_path, file_path = git_util.get_zip_path()
        if os.path.exists(file_path):
            os.remove(file_path)
        path_to_zip = make_archive(parent_path, "zip", parent_path)
        logger.info(parent_path, file_path, path_to_zip)
        response = FileResponse(open(path_to_zip, 'rb'))
        response['Content-Type'] = 'application/octet-stream'
        response['Content-Disposition'] = 'attachment;filename="{}"'.format(
            instance.model_name + ".zip")
        return response

    @action(detail=True, methods=['get'], url_path='experiments')
    def get_experiments(self, request, *args, **kwargs):
        """
        获取某个模型库下的所有实验
        """
        instance = self.get_object()
        experiment_list = Experiment.objects.filter(model_id=instance.id)
        page = self.paginate_queryset(experiment_list)
        serializer = ExperimentListSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)


class SnippetViewSet(viewsets.ModelViewSet):
    """
    此视图自动提供`list`，`create`，`retrieve`，`update`和`destroy`操作。

    另外我们还提供了一个额外的`highlight`操作。
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          )

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)
